package com.lwy.setter.setters;


import com.lwy.setter.BaseNameSetter;
import com.lwy.setter.NameSetterMeta;
import com.lwy.setter.annos.EnumValue;
import com.lwy.setter.enums.CnEnumCache;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import com.lwy.setter.types.StringOption;


import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <br/>
 *
 * @author bukong
 * @date 2022/7/5
 */
@Component
public class EnumValueNameSetter extends BaseNameSetter<EnumValue> {

    @Override
    public boolean isFillNameByCode() {
        return false;
    }

    @Override
    protected Class<EnumValue> getAnnotationClz() {
        return EnumValue.class;
    }

    @Override
    public <T> void fillNameById(List<T> beans, Class<T> tClass) {
        if (CollectionUtils.isEmpty(beans)) {
            return;
        }
        try {
            final Map<Field, Field> fieldMapper = NameSetterMeta.getFieldMapper(tClass, getAnnotationClz());
            Set<Long> ids = new HashSet<>();
            Map<String, Collection<String>> groupedDictValues = new HashMap<>();
            List<String> parentCodes = new ArrayList<>();
            for (Field markedField : fieldMapper.keySet()) {
                final EnumValue annotation = markedField.getAnnotation(getAnnotationClz());
                String typeCode = annotation.typeCode();
                for (T bean : beans) {
                    final Object markedFieldVal = markedField.get(bean);
                    if (markedFieldVal == null) {
                        continue;
                    } else {
                        final Collection<String> codes = groupedDictValues.computeIfAbsent(typeCode, (k) -> new HashSet<>());
                        if (markedFieldVal instanceof Number) {
                            codes.add(markedFieldVal.toString());
                        } else if (markedFieldVal instanceof Collection) {
                            List<String> beanIds = ((Collection<?>) markedFieldVal).stream().map(Object::toString).collect(Collectors.toList());
                            codes.addAll(beanIds);
                        }
                        groupedDictValues.put(typeCode, codes);
                    }
                }
            }
            // 查询名称
            Map<String, String> nameMap = new HashMap<>();
            for (Map.Entry<String, Collection<String>> entry : groupedDictValues.entrySet()) {
                Optional.ofNullable(CnEnumCache.getValueOptions(entry.getKey()))
                        .ifPresent(enumItems -> nameMap.putAll(enumItems.stream().collect(Collectors.toMap(item -> entry.getKey() + "#" + item.getValue(), StringOption::getLabel))));
            }
            for (Map.Entry<Field, Field> entry : fieldMapper.entrySet()) {
                final Field markedField = entry.getKey();
                final Field nameField = entry.getValue();
                for (T bean : beans) {
                    final Object markedFieldVal = markedField.get(bean);
                    final EnumValue annotation = markedField.getAnnotation(getAnnotationClz());
                    String parentCode = annotation.typeCode();
                    if (markedFieldVal == null) {
                        continue;
                    } else if (markedFieldVal instanceof Number) {
                        final String fieldNameKey = parentCode + "#" + markedFieldVal;
                        if (nameMap.containsKey(fieldNameKey)) {
                            nameField.set(bean, nameMap.get(fieldNameKey));
                        }
                    } else if (markedFieldVal instanceof Collection) {
                        List<String> markedFieldValues = ((Collection<?>) markedFieldVal).stream().map(Object::toString).collect(Collectors.toList());
                        List<String> nameList = markedFieldValues.stream()
                                .map(val -> parentCode + "#" + val)
                                .map(nameMap::get).collect(Collectors.toList());
                        nameField.set(bean, nameList);
                    }
                }
            }
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

}
